#ifndef __CONNECTOR_H__
#define __CONNECTOR_H__

#include "Spark/Utils/NonCopyable.h"
#include "Spark/Net/Socket.h"
#include "Spark/Net/CallbackDefs.h"
#include <functional>
#include <memory>
#include <atomic>

class EventLoop;
class Channel;

class Connector : public NonCopyable,
                  public std::enable_shared_from_this<Connector>
{
  public:
    enum class ConnectorState : int
    {
        Disconnected,
        Connecting,
        Connected
    };

    enum : int
    {
        kMaxRetryDeleyMs = 30 * 1000,
        kInitRetryDelayMs = 500
    };
    using NewConnectionCallback = std::function<void(int)>;
    Connector(EventLoop* loop, SocketAddr addr);
    ~Connector();
    void setNewConnectionCallback(NewConnectionCallback cb)
    {
        newConnectionCallback_ = std::move(cb);
    }

    void setConnectionErrorCallback(Callback_t cb)
    {
        errorCallback_ = std::move(cb);
    }

    void setRetry()
    {
        retry_ = true;
    }

    const SocketAddr& peerAddr() const
    {
        return peeraddr_;
    }

    void start();
    void restart();
    void stop();

  protected:
    void startInLoop();
    void stopInLoop();
    void connect();
    void connecting(int sockfd);
    int removeAndResetChannel();
    void handleWrite();
    void handleError();
    void retry(int sockfd);

  protected:
    EventLoop* loop_;
    SocketAddr peeraddr_;
    std::unique_ptr<Channel> channel_;
    NewConnectionCallback newConnectionCallback_;
    Callback_t errorCallback_;
    int retryInterval_{kInitRetryDelayMs};
    std::atomic_bool connect_{false};
    std::atomic<ConnectorState> state_{ConnectorState::Disconnected};
    bool retry_{false};
};

#endif  // __CONNECTOR_H__